﻿using CodeGenerator.CSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Modifier = CodeGenerator.CSharp.Modifiers;

namespace CodeAngel.Domain
{
    public static class DtoHostFileGenerator
    {
        #region CreateDtoHostFileAsync

        /// <summary>
        /// Creates and writes to disk the DTO files for the specified EntityDef.
        /// If these files already exists, they will be overwritten.
        /// </summary>
        public static Task CreateDtoHostFileAsync(this Domain thisDomain)
        {
            return Task.Factory.StartNew(() =>
            {
                DtoHostFileGenerator.WriteToDisk(thisDomain);
            });
        }

        #endregion

        #region WriteToDisk

        /// <summary>
        /// Creates and writes to disk the full-CLR DTO file. If this file already exists, 
        /// it will be overwritten.
        /// </summary>
        private static void WriteToDisk(Domain thisDomain)
        {
            var ThisFB = new FileBuilder();
            ThisFB.ProjectName = thisDomain.ProjectName;
            ThisFB.Directory = thisDomain.EntitiesPath;
            ThisFB.FileName = "DtoHost.cs";
            ThisFB.Namespace = thisDomain.DomainNamespace;
            ThisFB.IsAutoGenerated = true;

            // Add the using namespaces for this file.
            ThisFB.UsingNamespaces.Add("System");
            ThisFB.UsingNamespaces.Add("System.Collections.Generic");
            ThisFB.UsingNamespaces.Add("System.Runtime.Serialization");

            // Add the DTO class.
            ThisFB.CodeUnits.Add(new DtoHostClassBuilder(thisDomain));

            // Write this file to disk.
            ThisFB.WriteToDisk(OverwriteExistingFile.Yes);
        }

        #endregion

        #region DtoExtensionsClassBuilder

        /// <summary>
        /// Builds the DTOHost class - a collection of extension methods
        /// for DTO classes that need access to the full-CLR.
        /// </summary>
        private class DtoHostClassBuilder : ClassBuilder
        {
            #region Constructors

            public DtoHostClassBuilder(Domain thisDomain)
                : base("DtoHost", Modifier.Public)
            {
                this.Documentation.Summary = "A collection of DTOs designed for moving data from one system to another.";
                this.Attributes.Add("DataContract");
                

                // Adds the DTO properties.
                foreach (var ThisED in thisDomain.EntityDefs)
                {
                    //// Root DTOs
                    //string DataType = "List<" + ThisED.ClassNames.Dto() + ">";
                    //var ThisRegion = this.AddRegion(ThisED.Name.ToPlural());
                    //string RootBackingField = "_Root" + ThisED.Name.ToPlural();
                    //var RootDtosProperty = ThisRegion.AddProperty("Root" + ThisED.Name.ToPlural(), Modifier.Public, DataType, RootBackingField);
                    //RootDtosProperty.Documentation.Summary = "";
                    //RootDtosProperty.GetBody.Add("if (this.{0} == null) this.{0} = new {1}();", RootBackingField, DataType);
                    //RootDtosProperty.GetBody.Add("return this.{0};", RootBackingField);

                    //// Non-Root DTOs
                    //string BackingField = "_" + ThisED.Name.ToPlural();
                    //var DtosProperty = ThisRegion.AddProperty(ThisED.Name.ToPlural(), Modifier.Public, DataType, BackingField);
                    //DtosProperty.Documentation.Summary = "";
                    //DtosProperty.GetBody.Add("if (this.{0} == null) this.{0} = new {1}();", BackingField, DataType);
                    //DtosProperty.GetBody.Add("return this.{0};", BackingField);

                    // Root DTOs
                    string DataType = "List<" + ThisED.ClassNames.Dto() + ">";
                    var ThisRegion = this.AddRegion(ThisED.Name.ToPlural());
                    string RootBackingField = "_Root" + ThisED.Name.ToPlural();
                    var RootDtosProperty = ThisRegion.AddProperty("Root" + ThisED.Name.ToPlural(), Modifier.Public, DataType);
                    RootDtosProperty.Documentation.Summary = "";
                    RootDtosProperty.GetBody.Add("if (this.{0} == null) this.{0} = new {1}();", RootBackingField, DataType);
                    RootDtosProperty.GetBody.Add("return this.{0};", RootBackingField);
                    var RootDtosField = ThisRegion.AddField(RootBackingField, Modifier.Private, DataType);
                    RootDtosField.Attributes.Add("DataMember");

                    // Non-Root DTOs
                    string BackingField = "_" + ThisED.Name.ToPlural();
                    var DtosProperty = ThisRegion.AddProperty(ThisED.Name.ToPlural(), Modifier.Public, DataType);
                    DtosProperty.Documentation.Summary = "";
                    DtosProperty.GetBody.Add("if (this.{0} == null) this.{0} = new {1}();", BackingField, DataType);
                    DtosProperty.GetBody.Add("return this.{0};", BackingField);
                    var DtosField = ThisRegion.AddField(BackingField, Modifier.Private, DataType);
                    DtosField.Attributes.Add("DataMember");


                }

            #endregion

            }
            
            #endregion

        }
    }
}
